from dataclasses import dataclass
from datetime import datetime
from enum import IntEnum
from threading import Condition, Thread
from time import sleep
from typing import List

from emi import report
from emi.core.Context import Context
from emi.core.DBSource import DBSource
from emi.report import IReporter, ReportEvent, ReportEventType
from emi.report._impl import _ConsoleReporter
from emi.report.data import LogLevel, LogData
from emi.report.storage import LogDataDB

default_report_tags = ['MYSQL']

class DBReporter(_ConsoleReporter):

    def __init__(self, source: DBSource,tags:List[str] = []):
        """
        开辟一个后台线程，定时存储。
        """
        self.condition = Condition()  ## 并发锁
        self._thread = Thread(target=self._run_in_thread)  ##运行线程。
        self._logs_cache = []
        self.log_db = LogDataDB(source)
        self._thread.start()
        self._report_tags = tags

    def _on_log_data(self,log_data:LogData):
        self.condition.acquire()
        self._logs_cache.append(log_data)
        self.condition.notify()  ## 唤醒相关线程
        self.condition.release()

    def _run_in_thread(self):
        cur_day = datetime.now().date()
        while True:
            day_changed = cur_day != datetime.now().date()
            if day_changed:
                ###  清理之前天数的数据，只保留最近7天的数据。
                days = self.log_db.get_day_list()
                if len(days) > 7:
                    self.log_db.clear_before(day=days[-7])
            self.condition.acquire()
            save_logs = self._logs_cache
            self._logs_cache = []
            if len(save_logs) < 1:
                ## 没有日志的话，挂起
                ##print(f"[DBReporter], wait...")
                self.condition.wait()
            self.condition.release()
            if len(save_logs) > 0:
                ### 保存数据。
                ##print(f"[DBReporter], save logs: count = {len(save_logs)}")
                self.log_db.save_bars(save_logs)

    def report(self, event: ReportEvent):
        """
        上报花费时间。
        """
        if event.type == ReportEventType.LOG:
            log_data = LogData(
                level=LogLevel(event.sub_type),
                time=event.time,
                msg=event.msg,
                tag=event.name if event.name else "",
                exception_info=event.exception
            )
            if log_data.level >= LogLevel.WARN or (log_data.tag in self._report_tags) or (log_data.tag in default_report_tags):
                ## 需要存储的log
                self._on_log_data(log_data)
        super().report(event)